/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __FRAMEWORK_RENDERER_H__
#define __FRAMEWORK_RENDERER_H__


// All drawing is done to a 640x480 virtual screen size and will be
// automatically scaled to the real resolution
#define SCREEN_WIDTH				640
#define SCREEN_HEIGHT				480

// Scene limits
#define MAX_RENDER_ENTITIES			4096
#define MAX_RENDER_LIGHTS			1024
#define MAX_RENDER_PARTICLES		8192
#define MAX_RENDER_DECALS			1024

// Material parms
#define MAX_MATERIAL_PARMS			8

#define MATERIALPARM_RED			0			// Used by "colored" materials
#define MATERIALPARM_GREEN			1			// Used by "colored" materials
#define MATERIALPARM_BLUE			2			// Used by "colored" materials
#define MATERIALPARM_ALPHA			3			// Used by "colored" materials
#define MATERIALPARM_TIMEOFFSET		4			// Offset relative to renderView time
#define MATERIALPARM_DIVERSITY		5			// Random value for some effects
#define MATERIALPARM_MISC			6			// Used for various things throughout the code
#define MATERIALPARM_MODE			7			// For selecting which material stages to enable

// Render entity types
typedef enum {
	RE_MODEL,
	RE_SPRITE,
	RE_BEAM
} reType_t;

// Render light types
typedef enum {
	RL_POINT,
	RL_PROJECTED
} rlType_t;

// Render particle types
typedef enum {
	RP_VIEW,
	RP_ORIENTED,
	RP_AIMED
} rpType_t;

// View types for per-view allow/suppress
typedef enum {
	VIEW_NONE						= 0,
	VIEW_MAIN						= BIT(0),
	VIEW_PORTALSKY					= BIT(1),
	VIEW_MIRROR						= BIT(2),
	VIEW_PORTAL						= BIT(3),
	VIEW_REMOTE						= BIT(4),
	VIEW_ANY						= -1
} viewType_t;

typedef struct model_s				model_t;
typedef struct material_s			material_t;
typedef struct scene_s				scene_t;

typedef struct renderEntity_s {
	reType_t				type;

	int						entityNum;

	// Entities that are expensive to generate, like skeletal models, can be
	// deferred until their bounds are found to be in view, in the frustum of a
	// shadowing light that is in view, or contacted by a decal test
	void					(*callback)(struct renderEntity_s *);

	void *					callbackData;		// Used for whatever the callback wants

	// Transformation matrix
	odVec3					origin;
	odMat3					axis;

	// Model specific
	model_t *				model;

	odBounds				bounds;				// Frame bounds (only needed for skeletal models)

	odJointMat *			joints;				// Joint matrices for skeletal model skinning (NULL == default pose)

	// Sprite specific
	bool					spriteOriented;
	float					spriteRadius;
	float					spriteRotation;

	// Beam specific
	odVec3					beamEnd;
	float					beamWidth;
	float					beamLength;

	// Misc stuff
	struct renderView_s *	renderView;			// For portals and remote cameras

	int						allowInView;		// For per-view allow/suppress
	int						allowShadowInView;	// For per-view allow/suppress

	float					depthHack;			// Depth range hack to avoid poking into geometry (implies noShadows)

	// Material information
	material_t *			material;			// If not NULL, all surfaces will use this
	float					materialParms[MAX_MATERIAL_PARMS];
} renderEntity_t;

typedef struct renderLight_s {
	rlType_t				type;

	int						lightNum;

	// Transformation matrix
	odVec3					origin;
	odVec3					center;				// Offset relative to origin
	odMat3					axis;

	// Point light specific
	odVec3					radius;

	// Projected light specific
	float					fovX;
	float					fovY;

	float					falloffRange;

	// Light attributes
	bool					parallel;			// Light center gives the direction to the light at infinity
	bool					noShadows;			// Used to override material settings

	int						detailLevel;		// Light detail level

	int						allowInView;		// For per-view allow/suppress

	// Material information
	material_t *			material;			// If NULL, either _defaultPointLight or _defaultProjectedLight will be used
	float					materialParms[MAX_MATERIAL_PARMS];
} renderLight_t;

typedef struct renderParticle_s {
	rpType_t				type;

	// Transformation matrix
	odVec3					origin;
	odVec3					direction;			// For aimed particles
	odMat3					axis;				// For oriented particles

	// Particle attributes
	float					radius;
	float					rotation;			// Rotation angle for view and oriented particles
	float					length;				// Length for aimed particles (sparks, tracers, etc)

	byte					modulate[4];

	int						allowInView;		// For per-view allow/suppress

	// Material information
	material_t *			material;
} renderParticle_t;

typedef struct renderView_s {
	// Viewport definition
	int						x;
	int						y;
	int						width;
	int						height;

	float					fovX;
	float					fovY;

	// Transformation matrix
	odVec3					origin;
	odMat3					axis;

	// Origin of portal sky, if available
	odVec3					portalSkyOrigin;

	// Time in seconds for time dependent effects
	float					time;

	// Global material parms
	float					materialParms[MAX_MATERIAL_PARMS];
} renderView_t;

typedef struct {
	bool					initialized;

	const char *			vendorString;
	const char *			rendererString;
	const char *			versionString;
	const char *			extensionsString;
	const char *			wglExtensionsString;

	const char *			shadingLanguageVersionString;

	bool					textureNonPowerOfTwoAvailable;
	bool					textureFilterAnisotropicAvailable;
	bool					depthBoundsTestAvailable;
	bool					swapControlAvailable;

	int						maxTextureSize;
	int						maxCubeMapTextureSize;
	int						maxTextureUnits;
	int						maxTextureCoords;
	int						maxTextureImageUnits;
	int						maxVertexTextureImageUnits;
	int						maxCombinedTextureImageUnits;
	int						maxVertexAttribs;
	int						maxVaryingFloats;
	int						maxVertexUniformComponents;
	int						maxFragmentUniformComponents;
	float					maxTextureLODBias;
	float					maxTextureMaxAnisotropy;

	int						colorBits;
	int						alphaBits;
	int						depthBits;
	int						stencilBits;
	int						samples;

	bool					deviceSupportsGamma;
	bool					isFullscreen;
	int						videoWidth;
	int						videoHeight;
	int						displayFrequency;
} glConfig_t;

/*
 ==============================================================================

 FUNCTIONS EXPORTED BY THE ENGINE

 ==============================================================================
*/

typedef struct {
	// Loads and prepares the given map for rendering
	void					(*LoadMap)(const char *name);

	// Loads and registers the given model
	model_t *				(*RegisterModel)(const char *name);

	// Loads and registers the given material
	material_t *			(*RegisterMaterial)(const char *name);
	material_t *			(*RegisterMaterialLight)(const char *name);
	material_t *			(*RegisterMaterialNoMip)(const char *name);

	// Render scenes can be allocated and freed as needed.
	// The client will allocate a scene for rendering the game view, but other
	// parts of the program can also allocate scenes for other uses, like
	// drawing 3D items in the HUD, or displaying models in the GUI.
	scene_t *				(*AllocRenderScene)(int maxEntities, int maxLights, int maxParticles, int maxDecals);
	void					(*FreeRenderScene)(scene_t *scene);

	// Entities, lights, and particles must be added to a given scene to
	// determine what will be drawn for a given view. Most update work is
	// deferred until it is determined that it is actually needed for a given
	// view.
	// Nothing is drawn until R_RenderScene is called.
	int						(*AddRenderEntity)(scene_t *scene, const renderEntity_t *renderEntity);
	void					(*UpdateRenderEntity)(scene_t *scene, int entityHandle, const renderEntity_t *renderEntity);
	void					(*FreeRenderEntity)(scene_t *scene, int entityHandle);

	int						(*AddRenderLight)(scene_t *scene, const renderLight_t *renderLight);
	void					(*UpdateRenderLight)(scene_t *scene, int lightHandle, const renderLight_t *renderLight);
	void					(*FreeRenderLight)(scene_t *scene, int lightHandle);

	int						(*AddRenderParticle)(scene_t *scene, const renderParticle_t *renderParticle);
	void					(*UpdateRenderParticle)(scene_t *scene, int particleHandle, const renderParticle_t *renderParticle);
	void					(*FreeRenderParticle)(scene_t *scene, int particleHandle);

	// Projects a decal onto the world
	void					(*ProjectDecalOntoWorld)(scene_t *scene, const odVec3 &origin, const odVec3 &direction, float angle, float radius, float time, material_t *material);

	// Projects a decal onto the model of the given entity
	void					(*ProjectDecal)(scene_t *scene, int entityHandle, const odVec3 &origin, const odVec3 &direction, float angle, float radius, float time, material_t *material);

	// Removes all decals from the model of the given entity
	void					(*RemoveDecals)(scene_t *scene, int entityHandle);

	// Compiles all lights, generating lists of static interactions and
	// shadows.
	// If this isn't called after loading a map, all world interactions and
	// shadows will be dynamically generated.
	void					(*CompileLights)(scene_t *scene);

	// Rendering a scene may actually render multiple views for mirrors,
	// portals, remote cameras, and portal skies.
	// If primaryView is false, the world map will be ignored completely, which
	// is useful for rendering things like GUI models.
	void					(*RenderScene)(scene_t *scene, const renderView_t *renderView, bool primaryView);

	// 2D drawing just involves material parameter setting and axial image
	// subsections
	void					(*SetColor)(const odVec4 &color);
	void					(*SetColor4)(float r, float g, float b, float a);

	void					(*DrawStretchPic)(float x, float y, float w, float h, float s1, float t1, float s2, float t2, material_t *material);
	void					(*DrawShearedPic)(float x, float y, float w, float h, float s1, float t1, float s2, float t2, float xShear, float yShear, material_t *material);

	// To render to a texture, first set the crop size, then perform all
	// desired rendering, then capture to a texture.
	// The width and height values are in virtual 640x480 coordinates.
	// Users of the renderer will not know the actual pixel size of the area
	// they are rendering to.
	// If the specified physical dimensions are larger than the current cropped
	// region, they will be cut down to fit.
	void					(*CropRenderSize)(int width, int height, bool makePowerOfTwo);
	void					(*UnCrop)(void);

	// Captures the screen render to the given texture.
	// Returns false if the texture wasn't found or couldn't be dynamically
	// modified.
	bool					(*CaptureRenderToTexture)(const char *name);

	// Updates the given texture's image. The image data must be in RGBA
	// format, and the size must be a power of two.
	// Returns false if the texture wasn't found or couldn't be dynamically
	// modified.
	bool					(*UpdateTextureImage)(const char *name, const byte *image, int width, int height);

	// Allows other subsystems to get the current GL configuration
	void					(*GetGLConfig)(glConfig_t *config);
} odRenderer_t;


#endif	// __FRAMEWORK_RENDERER_H__
